package org.ielts.action;

import static com.yifeng.struts2.RequestParameters.*;
import static com.yifeng.struts2.ResultParameters.*;
import static com.yifeng.struts2.ResultConstants.*;
import static com.yifeng.struts2.ActionUtils.*;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sf.json.JSONArray;
import net.sf.json.JsonConfig;
import net.sf.json.util.CycleDetectionStrategy;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.ielts.domain.base.Classroom;
import org.ielts.domain.base.CourseType;
import org.ielts.domain.base.Lesson;
import org.ielts.domain.base.Teaching;
import org.ielts.domain.report.LessonWithListenerCount;
import org.ielts.domain.report.TeachingWithCount;
import org.ielts.domain.security.User;
import org.ielts.service.ClassroomService;
import org.ielts.service.CourseTypeService;
import org.ielts.service.LessonService;
import org.ielts.service.TeacherService;
import org.ielts.service.TeachingService;
import org.springframework.beans.factory.annotation.Autowired;

import com.yifeng.ProfileContext;
import com.yifeng.TimePair;
import com.yifeng.modules.annotations.Operation;
import com.yifeng.profile.Profile;
import com.yifeng.utils.JsonResultBuilder;

public class ScheduleAction extends BaseAction {
	@Autowired
	CourseTypeService courseTypeService;

	@Autowired
	ClassroomService classroomService;

	@Autowired
	TeachingService teachingService;

	@Autowired
	TeacherService teacherService;

	@Operation(result = FILL)
	public String viewScheduleByDay() {
		return FILL;
	}

	@Operation(result = FILL)
	public String listTeacherLesson() {
		String teacherId = form.readString("teacherId");

		if (StringUtils.isBlank(teacherId)) {
			teacherId = Profile.getInstance().getUserId();
		}

		Date startDate = valueReader.name("startDate").defaultValue(null).dateValue("yyyy-MM-dd");
		Date endDate = valueReader.name("endDate").defaultValue(null).dateValue("yyyy-MM-dd");
		if (endDate != null) {
			endDate = DateUtils.addDays(endDate, 1);
		}

		if (startDate == null || endDate == null) {
			Calendar calendar = Calendar.getInstance();
			calendar.setFirstDayOfWeek(Calendar.MONDAY);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

			startDate = calendar.getTime();
			startDate = DateUtils.truncate(startDate, Calendar.DATE);
			endDate = DateUtils.addDays(startDate, 7);
		}

		User teacher = teacherService.findOne(teacherId);
		put("teacher", teacher);

		Map<String, TimePair> timePairs = getWeekTimePairs(startDate);
		put("timePairs", timePairs);

		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);

		int week = startCalendar.get(Calendar.WEEK_OF_YEAR);
		put("week", week);

		put("startDate", startDate);
		endDate = DateUtils.addDays(endDate, -1);
		put("endDate", endDate);

		teachingsWithCount = teachingService.findReportBetweenDateAndTeacher(startDate, endDate, teacherId);

		return FILL;
	}

	Iterable<TeachingWithCount> teachingsWithCount;

	public Iterable<TeachingWithCount> findReportByTeacherAndDay(User teacher, TimePair timePair) {
		ArrayList<TeachingWithCount> returnList = new ArrayList<TeachingWithCount>();

		for (TeachingWithCount teachingWithCount : teachingsWithCount) {
			if (teachingWithCount.getTeaching().getTeacher().equals(teacher)) {
				TimePair teachingTimePair = new TimePair();
				teachingTimePair.setStartDate(teachingWithCount.getTeaching().getBeginTime());
				teachingTimePair.setEndDate(teachingWithCount.getTeaching().getEndTime());

				if (timePair.isContaineTime(teachingTimePair)) {
					returnList.add(teachingWithCount);
				}
			}
		}

		return returnList;
	}

	@Operation(result = FILL)
	public String listTypeLesson() {
		String courseTypeId = form.readString("courseTypeId");
		Date startDate = valueReader.name("startDate").defaultValue(null).dateValue("yyyy-MM-dd");
		Date endDate = valueReader.name("endDate").defaultValue(null).dateValue("yyyy-MM-dd");
		if (endDate != null) {
			endDate = DateUtils.addDays(endDate, 1);
		}

		if (startDate == null || endDate == null) {
			Calendar calendar = Calendar.getInstance();
			calendar.setFirstDayOfWeek(Calendar.MONDAY);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

			startDate = calendar.getTime();
			startDate = DateUtils.truncate(startDate, Calendar.DATE);
			endDate = DateUtils.addDays(startDate, 7);
		}

		CourseType courseType = courseTypeService.findOne(courseTypeId);
		put("courseType", courseType);

		Map<String, TimePair> timePairs = getWeekTimePairs(startDate);
		put("timePairs", timePairs);

		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);

		int week = startCalendar.get(Calendar.WEEK_OF_YEAR);
		put("week", week);

		put("startDate", startDate);
		endDate = DateUtils.addDays(endDate, -1);
		put("endDate", endDate);

		lessonsWithCount = lessonService.findReportBetweenDateAndCourseType(startDate, endDate, courseTypeId);

		return FILL;
	}

	public Iterable<LessonWithListenerCount> findReportByTypeAndDay(CourseType courseType, TimePair timePair) {
		ArrayList<LessonWithListenerCount> returnList = new ArrayList<LessonWithListenerCount>();

		for (LessonWithListenerCount lessonWithListenerCount : lessonsWithCount) {
			if (lessonWithListenerCount.getLesson().getCourseType().equals(courseType)) {
				TimePair classroomTimePair = new TimePair();
				classroomTimePair.setStartDate(lessonWithListenerCount.getLesson().getBeginTime());
				classroomTimePair.setEndDate(lessonWithListenerCount.getLesson().getEndTime());

				if (timePair.isContaineTime(classroomTimePair)) {
					returnList.add(lessonWithListenerCount);
				}
			}
		}

		return returnList;
	}

	@Operation(result = FILL)
	public String listClassroomLesson() {
		String classroomId = form.readString("classroomId");
		Date startDate = valueReader.name("startDate").defaultValue(null).dateValue("yyyy-MM-dd");
		Date endDate = valueReader.name("endDate").defaultValue(null).dateValue("yyyy-MM-dd");
		if (endDate != null) {
			endDate = DateUtils.addDays(endDate, 1);
		}

		if (startDate == null || endDate == null) {
			Calendar calendar = Calendar.getInstance();
			calendar.setFirstDayOfWeek(Calendar.MONDAY);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

			startDate = calendar.getTime();
			startDate = DateUtils.truncate(startDate, Calendar.DATE);
			endDate = DateUtils.addDays(startDate, 7);
		}

		Classroom classroom = classroomService.findOne(classroomId);
		put("classroom", classroom);

		Map<String, TimePair> timePairs = getWeekTimePairs(startDate);
		put("timePairs", timePairs);

		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);

		int week = startCalendar.get(Calendar.WEEK_OF_YEAR);
		put("week", week);

		put("startDate", startDate);
		endDate = DateUtils.addDays(endDate, -1);
		put("endDate", endDate);

		lessonsWithCount = lessonService.findReportBetweenTimeAndClassroom(startDate, endDate, classroomId);

		return FILL;
	}

	Iterable<LessonWithListenerCount> lessonsWithCount;

	public Iterable<LessonWithListenerCount> findReportByClassroomAndDay(Classroom classroom, TimePair timePair) {
		ArrayList<LessonWithListenerCount> returnList = new ArrayList<LessonWithListenerCount>();

		for (LessonWithListenerCount lessonWithListenerCount : lessonsWithCount) {
			if (lessonWithListenerCount.getLesson().getClassroom().equals(classroom)) {
				TimePair classroomTimePair = new TimePair();
				classroomTimePair.setStartDate(lessonWithListenerCount.getLesson().getBeginTime());
				classroomTimePair.setEndDate(lessonWithListenerCount.getLesson().getEndTime());

				if (timePair.isContaineTime(classroomTimePair)) {
					returnList.add(lessonWithListenerCount);
				}
			}
		}

		return returnList;
	}

	public boolean isInLessonsConflict(Iterable<Lesson> lessons) {
		ArrayList<TimePair> pairs = new ArrayList<TimePair>();

		for (Lesson lesson : lessons) {
			TimePair lessonTimePair = new TimePair();
			lessonTimePair.setStartDate(lesson.getBeginTime());
			lessonTimePair.setEndDate(lesson.getEndTime());

			for (TimePair timePair : pairs) {
				if (timePair.isContaineTime(lessonTimePair)) {
					return true;
				}
			}

			pairs.add(lessonTimePair);
		}

		return false;
	}

	public boolean isInTeachingsConflict(Iterable<Teaching> teachings) {
		ArrayList<TimePair> pairs = new ArrayList<TimePair>();

		for (Teaching teaching : teachings) {
			TimePair lessonTimePair = new TimePair();
			lessonTimePair.setStartDate(teaching.getBeginTime());
			lessonTimePair.setEndDate(teaching.getEndTime());

			for (TimePair timePair : pairs) {
				if (timePair.isContaineTime(lessonTimePair)) {
					return true;
				}
			}

			pairs.add(lessonTimePair);
		}

		return false;
	}

	public Iterable<Lesson> findByCourseTypeAndDay(CourseType courseType, TimePair timePair) {
		ArrayList<Lesson> returnList = new ArrayList<Lesson>();

		for (Lesson lesson : lessons) {
			if (lesson.getCourseType().equals(courseType)) {
				TimePair teachingTimePair = new TimePair();
				teachingTimePair.setStartDate(lesson.getBeginTime());
				teachingTimePair.setEndDate(lesson.getEndTime());

				if (timePair.isContaineTime(teachingTimePair)) {
					returnList.add(lesson);
				}
			}
		}

		return returnList;
	}

	public String getFormateDay(Date date) {

		return new SimpleDateFormat("yyyy-MM-dd").format(date);
	}

	public Map<String, TimePair> getWeekTimePairs(Date startDate) {
		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);
		int year = startCalendar.get(Calendar.YEAR);
		int month = startCalendar.get(Calendar.MONTH);
		int day = startCalendar.get(Calendar.DAY_OF_MONTH);

		return getWeekTimePairs(year, month, day);

	}

	public Map<String, TimePair> getWeekTimePairs(int year, int month, int day) {
		Map<String, TimePair> pairs = new LinkedHashMap<String, TimePair>();

		String[] arrays = new String[] { "周一", "周二", "周三", "周四", "周五", "周六", "周日" };

		for (int i = 0; i < 7; i++) {
			String name = arrays[i];
			Date startDate = new Date();
			startDate = DateUtils.setYears(startDate, year);
			startDate = DateUtils.setMonths(startDate, month);
			startDate = DateUtils.setDays(startDate, day);
			startDate = DateUtils.addDays(startDate, i);
			startDate = DateUtils.truncate(startDate, Calendar.DATE);

			Date endDate = new Date();
			endDate = DateUtils.setYears(endDate, year);
			endDate = DateUtils.setMonths(endDate, month);
			endDate = DateUtils.setDays(endDate, day);
			endDate = DateUtils.addDays(endDate, i + 1);
			endDate = DateUtils.truncate(endDate, Calendar.DATE);

			TimePair timePair = new TimePair();
			timePair.setStartDate(startDate);
			timePair.setEndDate(endDate);

			pairs.put(name, timePair);
		}

		return pairs;
	}

	@Operation(result = FILL)
	public String listCourseTypesLessonByWeek() {
		Date startDate = valueReader.name("startDate").defaultValue(null).dateValue("yyyy-MM-dd");
		Date endDate = valueReader.name("endDate").defaultValue(null).dateValue("yyyy-MM-dd");
		if (endDate != null) {
			endDate = DateUtils.addDays(endDate, 1);
		}

		if (startDate == null || endDate == null) {
			Calendar calendar = Calendar.getInstance();
			calendar.setFirstDayOfWeek(Calendar.MONDAY);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

			startDate = calendar.getTime();
			startDate = DateUtils.truncate(startDate, Calendar.DATE);
			endDate = DateUtils.addDays(startDate, 7);
		}

		lessons = lessonService.findBetweenTime(startDate, endDate);

		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);
		int year = startCalendar.get(Calendar.YEAR);
		int month = startCalendar.get(Calendar.MONTH);
		int day = startCalendar.get(Calendar.DAY_OF_MONTH);

		int week = startCalendar.get(Calendar.WEEK_OF_YEAR);

		Iterable<CourseType> courseTypes = courseTypeService.findAll();
		List<TimePair> timePairs = buildWeekPairs(year, month, day);

		put("timePairs", timePairs);
		put("courseTypes", courseTypes);

		put("startDate", startDate);
		endDate = DateUtils.addDays(endDate, -1);
		put("endDate", endDate);
		put("week", week);

		return FILL;
	}

	@Operation(result = FILL)
	public String listTeachersLessonByWeek() {
		Date startDate = valueReader.name("startDate").defaultValue(null).dateValue("yyyy-MM-dd");
		Date endDate = valueReader.name("endDate").defaultValue(null).dateValue("yyyy-MM-dd");
		if (endDate != null) {
			endDate = DateUtils.addDays(endDate, 1);
		}

		if (startDate == null || endDate == null) {
			Calendar calendar = Calendar.getInstance();
			calendar.setFirstDayOfWeek(Calendar.MONDAY);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

			startDate = calendar.getTime();
			startDate = DateUtils.truncate(startDate, Calendar.DATE);
			endDate = DateUtils.addDays(startDate, 7);
		}

		teachings = teachingService.findBetweenDate(startDate, endDate);

		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);
		int year = startCalendar.get(Calendar.YEAR);
		int month = startCalendar.get(Calendar.MONTH);
		int day = startCalendar.get(Calendar.DAY_OF_MONTH);

		int week = startCalendar.get(Calendar.WEEK_OF_YEAR);

		Iterable<User> teachers = teacherService.findAll();
		List<TimePair> timePairs = buildWeekPairs(year, month, day);

		put("timePairs", timePairs);
		put("teachers", teachers);

		put("startDate", startDate);
		endDate = DateUtils.addDays(endDate, -1);
		put("endDate", endDate);
		put("week", week);

		return FILL;
	}

	@Operation(result = FILL)
	public String listClassroomsLessonByWeek() {
		Date startDate = valueReader.name("startDate").defaultValue(null).dateValue("yyyy-MM-dd");
		Date endDate = valueReader.name("endDate").defaultValue(null).dateValue("yyyy-MM-dd");
		if (endDate != null) {
			endDate = DateUtils.addDays(endDate, 1);
		}

		if (startDate == null || endDate == null) {
			Calendar calendar = Calendar.getInstance();
			calendar.setFirstDayOfWeek(Calendar.MONDAY);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

			startDate = calendar.getTime();
			startDate = DateUtils.truncate(startDate, Calendar.DATE);
			endDate = DateUtils.addDays(startDate, 7);
		}

		lessons = lessonService.findBetweenTime(startDate, endDate);

		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);
		int year = startCalendar.get(Calendar.YEAR);
		int month = startCalendar.get(Calendar.MONTH);
		int day = startCalendar.get(Calendar.DAY_OF_MONTH);

		int week = startCalendar.get(Calendar.WEEK_OF_YEAR);

		List<TimePair> timePairs = buildWeekPairs(year, month, day);
		Iterable<Classroom> classrooms = classroomService.findAll();

		put("timePairs", timePairs);
		put("classrooms", classrooms);

		put("startDate", startDate);
		endDate = DateUtils.addDays(endDate, -1);
		put("endDate", endDate);

		put("week", week);

		return FILL;
	}

	Iterable<Teaching> teachings;

	public Iterable<Teaching> findByTeacherAndDay(User teacher, TimePair timePair) {
		ArrayList<Teaching> returnList = new ArrayList<Teaching>();

		for (Teaching teaching : teachings) {
			if (teaching.getTeacher().equals(teacher)) {
				TimePair teachingTimePair = new TimePair();
				teachingTimePair.setStartDate(teaching.getBeginTime());
				teachingTimePair.setEndDate(teaching.getEndTime());

				if (timePair.isContaineTime(teachingTimePair)) {
					returnList.add(teaching);
				}
			}
		}

		return returnList;
	}

	public int countTeachings(User teacher, Date startDate, Date endDate) {
		TimePair timePair = new TimePair();
		timePair.setStartDate(startDate);
		timePair.setEndDate(endDate);
		int i = 0;
		for (Teaching teaching : teachings) {
			if (teaching.getTeacher().equals(teacher)) {
				TimePair teachingTimePair = new TimePair();
				teachingTimePair.setStartDate(teaching.getBeginTime());
				teachingTimePair.setEndDate(teaching.getEndTime());

				if (timePair.isContaineTime(teachingTimePair)) {
					i++;
				}
			}
		}

		return i;
	}

	public String sumTeachings(User teacher, Date startDate, Date endDate) {
		TimePair timePair = new TimePair();
		timePair.setStartDate(startDate);
		timePair.setEndDate(endDate);

		double time = 0;
		for (Teaching teaching : teachings) {
			if (teaching.getTeacher().equals(teacher)) {
				TimePair teachingTimePair = new TimePair();
				teachingTimePair.setStartDate(teaching.getBeginTime());
				teachingTimePair.setEndDate(teaching.getEndTime());

				if (timePair.isContaineTime(teachingTimePair)) {
					time += (teaching.getEndTime().getTime() - teaching.getBeginTime().getTime());
				}
			}
		}

		double hours = time / (1000 * 60 * 60);

		String result = String.format("%.1f", hours);

		return result;
	}

	List<TimePair> buildWeekPairs(int year, int month, int day) {
		ArrayList<TimePair> pairs = new ArrayList<TimePair>();

		for (int i = 0; i < 7; i++) {
			Date startDate = new Date();
			startDate = DateUtils.setYears(startDate, year);
			startDate = DateUtils.setMonths(startDate, month);
			startDate = DateUtils.setDays(startDate, day);
			startDate = DateUtils.addDays(startDate, i);
			startDate = DateUtils.truncate(startDate, Calendar.DATE);

			Date endDate = new Date();
			endDate = DateUtils.setYears(endDate, year);
			endDate = DateUtils.setMonths(endDate, month);
			endDate = DateUtils.setDays(endDate, day);
			endDate = DateUtils.addDays(endDate, i + 1);
			endDate = DateUtils.truncate(endDate, Calendar.DATE);

			TimePair timePair = new TimePair();
			timePair.setStartDate(startDate);
			timePair.setEndDate(endDate);

			pairs.add(timePair);
		}

		return pairs;
	}

	Iterable<Lesson> lessons;

	public Iterable<Lesson> findByClassroomAndDay(Classroom classroom, TimePair timePair) {
		ArrayList<Lesson> returnList = new ArrayList<Lesson>();

		for (Lesson lesson : lessons) {
			if (lesson.getClassroom().equals(classroom)) {
				TimePair classroomTimePair = new TimePair();
				classroomTimePair.setStartDate(lesson.getBeginTime());
				classroomTimePair.setEndDate(lesson.getEndTime());

				if (timePair.isContaineTime(classroomTimePair)) {
					returnList.add(lesson);
				}
			}
		}

		return returnList;
	}

	@Autowired
	LessonService lessonService;

	@Operation(result = FILL)
	public String listForeignTeaching() {
		Date startDate = valueReader.name("startDate").defaultValue(null).dateValue("yyyy-MM-dd");
		Date endDate = valueReader.name("endDate").defaultValue(null).dateValue("yyyy-MM-dd");
		if (endDate != null) {
			endDate = DateUtils.addDays(endDate, 1);
		}

		if (startDate == null || endDate == null) {
			Calendar calendar = Calendar.getInstance();
			calendar.setFirstDayOfWeek(Calendar.MONDAY);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

			startDate = calendar.getTime();
			startDate = DateUtils.truncate(startDate, Calendar.DATE);
			endDate = DateUtils.addDays(startDate, 7);
		}

		teachings = teachingService.findBetweenDate(startDate, endDate);

		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);
		Map<String, TimePair> timePairs = getWeekTimePairs(startDate);

		Iterable<User> teachers = teacherService.findAll();

		put("timePairs", timePairs);
		put("teachers", teachers);

		put("startDate", startDate);
		endDate = DateUtils.addDays(endDate, -1);
		put("endDate", endDate);

		int week = startCalendar.get(Calendar.WEEK_OF_YEAR);
		put("week", week);

		return FILL;
	}

	@Operation(result = FILL)
	public String listCancelTeaching() {
		Date startDate = valueReader.name("startDate").defaultValue(null).dateValue("yyyy-MM-dd");
		Date endDate = valueReader.name("endDate").defaultValue(null).dateValue("yyyy-MM-dd");
		if (endDate != null) {
			endDate = DateUtils.addDays(endDate, 1);
		}

		if (startDate == null || endDate == null) {
			Calendar calendar = Calendar.getInstance();
			calendar.setFirstDayOfWeek(Calendar.MONDAY);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

			startDate = calendar.getTime();
			startDate = DateUtils.truncate(startDate, Calendar.DATE);
			endDate = DateUtils.addDays(startDate, 7);
		}

		teachings = teachingService.findBetweenDate(startDate, endDate);

		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);
		Map<String, TimePair> timePairs = getWeekTimePairs(startDate);

		Iterable<User> teachers = teacherService.findAll();

		put("timePairs", timePairs);
		put("teachers", teachers);

		put("startDate", startDate);
		endDate = DateUtils.addDays(endDate, -1);
		put("endDate", endDate);

		int week = startCalendar.get(Calendar.WEEK_OF_YEAR);
		put("week", week);

		return FILL;
	}

	public Iterable<Teaching> findByTeacherAndDayCancel(User teacher, TimePair timePair) {
		ArrayList<Teaching> returnList = new ArrayList<Teaching>();

		for (Teaching teaching : teachings) {

			if (!teaching.getLesson().isCanceled()) {
				continue;
			}

			if (teaching.getTeacher().equals(teacher)) {
				TimePair teachingTimePair = new TimePair();
				teachingTimePair.setStartDate(teaching.getBeginTime());
				teachingTimePair.setEndDate(teaching.getEndTime());

				if (timePair.isContaineTime(teachingTimePair)) {
					returnList.add(teaching);
				}
			}
		}

		return returnList;
	}

	public Iterable<Teaching> findByTeacherAndDayNormal(User teacher, TimePair timePair) {
		ArrayList<Teaching> returnList = new ArrayList<Teaching>();

		for (Teaching teaching : teachings) {
			if (teaching.getLesson().isCanceled()) {
				continue;
			}

			if (teaching.getTeacher().equals(teacher)) {
				TimePair teachingTimePair = new TimePair();
				teachingTimePair.setStartDate(teaching.getBeginTime());
				teachingTimePair.setEndDate(teaching.getEndTime());

				if (timePair.isContaineTime(teachingTimePair)) {
					returnList.add(teaching);
				}
			}
		}

		return returnList;
	}
}
